<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
<!-- designer-manual.qdoc -->
  <title>创建自定义小部件（Widgets） | Qt Designer 手册</title>
  <link rel="stylesheet" type="text/css" href="style/offline-simple.css" />
  <script type="text/javascript">
    document.getElementsByTagName("link").item(0).setAttribute("href", "style/offline.css");
    // loading style sheet breaks anchors that were jumped to before
    // so force jumping to anchor again
    setTimeout(function() {
        var anchor = location.hash;
        // need to jump to different anchor first (e.g. none)
        location.hash = "#";
        setTimeout(function() {
            location.hash = anchor;
        }, 0);
    }, 0);
  </script>
</head>
<body>
<div class="header" id="qtdocheader">
  <div class="main">
    <div class="main-rounded">
      <div class="navigationbar">
        <table><tr>
<td ><a href="../qtdoc/index.html">Qt 5.14</a></td><td ><a href="qtdesigner-manual.html">Qt Designer 手册</a></td><td >创建自定义小部件（Widgets）</td></tr></table><table class="buildversion"><tr>
<td id="buildversion" width="100%" align="right"><a href="qtdesigner-manual.html">Qt 5.14.2 参考文档</a></td>
        </tr></table>
      </div>
    </div>
<div class="content">
<div class="line">
<div class="content mainContent">
  <link rel="prev" href="designer-using-custom-widgets.html" />
  <link rel="next" href="designer-creating-custom-widgets-extensions.html" />
<p class="naviNextPrevious headerNavi">
<a class="prevPage" href="designer-using-custom-widgets.html">使用自定义小部件（Widgets）</a>
<span class="naviSeparator">  &#9702;  </span>
<a class="nextPage" href="designer-creating-custom-widgets-extensions.html">创建自定义小部件(Widget)扩展</a>
</p><p/>
<div class="sidebar">
<div class="toc">
<h3><a name="toc">Contents</a></h3>
<ul>
<li class="level1"><a href="#getting-started">开始</a></li>
<li class="level2"><a href="#providing-an-interface-description">提供接口描述</a></li>
<li class="level2"><a href="#notes-on-the-domxml-function">关于 domXml() 函数的说明</code> Function</a></li>
<li class="level1"><a href="#plugin-requirements">插件的需求</a></li>
<li class="level1"><a href="#creating-well-behaved-widgets">创建表现良好的小部件</a></li>
<li class="level1"><a href="#building-and-installing-the-plugin">构建和安装插件</a></li>
<li class="level2"><a href="#a-simple-plugin">一个简单的插件</a></li>
<li class="level2"><a href="#splitting-up-the-plugin">分解插件</a></li>
<li class="level1"><a href="#related-examples">相关的例子</a></li>
</ul>
</div>
<div class="sidebar-content" id="sidebar-content"></div></div>
<h1 class="title">创建自定义小部件（Widgets）</h1>
<span class="subtitle"></span>
<!-- $$$designer-creating-custom-widgets.html-description -->
<div class="descr"> <a name="details"></a>
<p><i>Qt Designer</i> 的基于插件的架构允许编辑用户定义的和第三方自定义的小部件，就像你做的标准Qt小部件。<i>Qt Designer</i> 可以使用自定义小部件的所有特性，包括小部件属性、信号和槽。由于 <i>Qt Designer</i> 在窗体设计过程中使用了真实的小部件，因此自定义小部件的显示方式与预览时相同。</p>
<p class="centerAlign"><img src="images/worldtimeclockplugin-example.png" alt="" /></p><p><a href="qtdesigner-module.html">QtDesigner</a> 模块为您提供了在 <i>Qt Designer</i> 中创建定制小部件的能力。</p>
<a name="getting-started"></a>
<h2 id="getting-started">开始</h2>
<p>要将自定义小部件与 <i>Qt Designer</i> 集成，您需要小部件的适当描述和 <code>.pro</code> 文件。</p>
<a name="providing-an-interface-description"></a>
<h3 id="providing-an-interface-description">提供接口描述</h3>
<p>要将您想要提供的小部件的类型通知 <i>Qt Designer</i> ，请创建 <a href="qdesignercustomwidgetinterface.html">QDesignerCustomWidgetInterface</a> 的一个子类，该子类描述您的小部件公开的各种属性。其中大部分是由基类中的纯虚函数提供的，因为只有插件的作者才能提供这些信息。</p>
<div class="table"><table class="generic">
 <thead><tr class="qt-style"><th >函数</th><th >返回值的描述</th></tr></thead>
<tr valign="top" class="odd"><td ><code>name()</code></td><td >提供小部件的类的名称。</td></tr>
<tr valign="top" class="even"><td ><code>group()</code></td><td ><i>Qt Designer</i> 的小部件所在的组 。</td></tr>
<tr valign="top" class="odd"><td ><code>toolTip()</code></td><td >简短描述，帮助用户识别 <i>Qt Designer</i> 中的小部件 。</td></tr>
<tr valign="top" class="even"><td ><code>whatsThis()</code></td><td ><i>Qt Designer</i> 的用户对小部件的更长的描述。</td></tr>
<tr valign="top" class="odd"><td ><code>includeFile()</code></td><td >必须包含在使用此小部件的应用程序中的头文件。该信息存储在UI文件中，<code>uic</code> 将使用它在为包含自定义小部件的窗体生成的代码中创建合适的 <code>#includes</code> 语句 。</td></tr>
<tr valign="top" class="even"><td ><code>icon()</code></td><td >可用于表示 <i>Qt Designer</i> 的小部件框中的小部件的图标。</td></tr>
<tr valign="top" class="odd"><td ><code>isContainer()</code></td><td >如果小部件将用于容纳子小部件，则为 True ，否则 false 。</td></tr>
<tr valign="top" class="even"><td ><code>createWidget()</code></td><td >指向自定义小部件实例的 <a href="../qtwidgets/qwidget.html">QWidget</a> 指针，使用提供的父部件构造 。<p><b>注意: </b> createWidget() 是一个工厂函数，只负责创建小部件 。在 load() 返回之前，自定义小部件的属性将不可用 。</p></td></tr>
<tr valign="top" class="odd"><td ><code>domXml()</code></td><td >小部件属性的描述，例如它的对象名称、大小提示和其他标准 <a href="../qtwidgets/qwidget.html">QWidget</a> 属性 。</td></tr>
<tr valign="top" class="even"><td ><code>codeTemplate()</code></td><td >这个函数是 <i>Qt Designer</i> 为将来保留的。</td></tr>
</table></div>
<p>另外两个虚函数也可以重新实现:</p>
<div class="table"><table class="generic">
 <tr valign="top" class="odd"><td ><code>initialize()</code></td><td >为自定义小部件设置扩展和其他特性 。应该在这个函数中设置自定义容器扩展 (参见 <a href="qdesignercontainerextension.html">QDesignerContainerExtension</a> ) 和任务菜单扩展 (参见 <a href="qdesignertaskmenuextension.html">QDesignerTaskMenuExtension</a> ) 。</td></tr>
<tr valign="top" class="even"><td ><code>isInitialized()</code></td><td >如果小部件已经初始化，则返回 true ; 否则返回 false 。重新实现通常检查 <code>initialize()</code> 函数是否被调用 ， 并返回此测试的结果 。</td></tr>
</table></div>
<a name="notes-on-the-domxml-function"></a>
<h3 id="notes-on-the-domxml-function">关于 <code>domXml()</code> 函数的说明</h3>
<p><code>domXml()</code> 函数返回一个UI文件片段，<i>Qt Designer</i> 的小部件工厂使用该片段创建自定义小部件及其适用属性 。</p>
<p>自Qt 4.4, <i>Qt Designer</i> 的 widget box 允许一个完整的UI文件来描述 <b>一个</b> 定制的小部件 。UI文件可以使用 <code>&lt;ui&gt;</code> 标签。指定 &lt;ui&gt; 标签允许添加 &lt;customwidget&gt; 元素，其中包含用于自定义小部件的附加信息。如果不需要额外的信息，<code>&lt;widget&gt;</code> 标签就足够了 。</p>
<p>如果自定义小部件没有提供合理的大小提示，则有必要在子类中 <code>domXml()</code> 函数返回的字符串中指定默认几何形状 。例如， <a href="qtdesigner-customwidgetplugin-example.html">自定义Widget插件Custom Widget Plugin</a> 示例提供的 <code>AnalogClockPlugin</code> ，以下列方式定义默认的小部件几何形状 :</p>
<pre class="cpp">

      ...
             <span class="string">&quot;  &lt;property name=\&quot;geometry\&quot;&gt;\n&quot;</span>
             <span class="string">&quot;   &lt;rect&gt;\n&quot;</span>
             <span class="string">&quot;    &lt;x&gt;0&lt;/x&gt;\n&quot;</span>
             <span class="string">&quot;    &lt;y&gt;0&lt;/y&gt;\n&quot;</span>
             <span class="string">&quot;    &lt;width&gt;100&lt;/width&gt;\n&quot;</span>
             <span class="string">&quot;    &lt;height&gt;100&lt;/height&gt;\n&quot;</span>
             <span class="string">&quot;   &lt;/rect&gt;\n&quot;</span>
             <span class="string">&quot;  &lt;/property&gt;\n&quot;</span>
      ...

</pre>
<p><code>domXml()</code> 函数的另一个特性是，如果它返回一个空字符串，那么小部件将不会安装在 <i>Qt Designer</i> 的 Widget Box 中。但是，窗体中的其他小部件仍然可以使用它。此特性用于隐藏用户不应显式创建但其他小部件需要的小部件。</p>
<p>一个完整的自定义小部件规范如下:</p>
<pre class="cpp">

  <span class="operator">&lt;</span>ui language<span class="operator">=</span><span class="string">&quot;c++&quot;</span><span class="operator">&gt;</span> displayname<span class="operator">=</span><span class="string">&quot;MyWidget&quot;</span><span class="operator">&gt;</span>
      <span class="operator">&lt;</span>widget <span class="keyword">class</span><span class="operator">=</span><span class="string">&quot;widgets::MyWidget&quot;</span> name<span class="operator">=</span><span class="string">&quot;mywidget&quot;</span><span class="operator">/</span><span class="operator">&gt;</span>
      <span class="operator">&lt;</span>customwidgets<span class="operator">&gt;</span>
          <span class="operator">&lt;</span>customwidget<span class="operator">&gt;</span>
              <span class="operator">&lt;</span><span class="keyword">class</span><span class="operator">&gt;</span>widgets<span class="operator">::</span>MyWidget<span class="operator">&lt;</span><span class="operator">/</span><span class="keyword">class</span><span class="operator">&gt;</span>
              <span class="operator">&lt;</span>addpagemethod<span class="operator">&gt;</span>addPage<span class="operator">&lt;</span><span class="operator">/</span>addpagemethod<span class="operator">&gt;</span>
              <span class="operator">&lt;</span>propertyspecifications<span class="operator">&gt;</span>
                  <span class="operator">&lt;</span>stringpropertyspecification name<span class="operator">=</span><span class="string">&quot;fileName&quot;</span> notr<span class="operator">=</span><span class="string">&quot;true&quot;</span> type<span class="operator">=</span><span class="string">&quot;singleline&quot;</span><span class="operator">/</span><span class="operator">&gt;</span>
                  <span class="operator">&lt;</span>stringpropertyspecification name<span class="operator">=</span><span class="string">&quot;text&quot;</span> type<span class="operator">=</span><span class="string">&quot;richtext&quot;</span><span class="operator">/</span><span class="operator">&gt;</span>
                  <span class="operator">&lt;</span>tooltip name<span class="operator">=</span><span class="string">&quot;text&quot;</span><span class="operator">&gt;</span>Explanatory text to be shown in Property Editor<span class="operator">&lt;</span><span class="operator">/</span>tooltip<span class="operator">&gt;</span>
              <span class="operator">&lt;</span><span class="operator">/</span>propertyspecifications<span class="operator">&gt;</span>
          <span class="operator">&lt;</span><span class="operator">/</span>customwidget<span class="operator">&gt;</span>
      <span class="operator">&lt;</span><span class="operator">/</span>customwidgets<span class="operator">&gt;</span>
  <span class="operator">&lt;</span><span class="operator">/</span>ui<span class="operator">&gt;</span>

</pre>
<p>&lt;ui&gt; 标签的属性:</p>
<div class="table"><table class="generic">
 <thead><tr class="qt-style"><th >属性</th><th >存在</th><th >值</th><th >评论</th></tr></thead>
<tr valign="top" class="odd"><td ><code>language</code></td><td >可选</td><td >&quot;c++&quot;, &quot;jambi&quot;</td><td >此属性指定自定义小部件要使用的语言。主要是为了防止 c++ 插件出现在 Qt Jambi 中。
</td></tr>
<tr valign="top" class="even"><td ><code>displayname</code></td><td >可选</td><td >类名</td><td >该属性的值出现在 Widget box 中，可用于去除名称空间。</td></tr>
</table></div>
<p><code>&lt;addpagemethod&gt;</code> 标记告诉 <i>Qt Designer</i> 和 <a href="../qtdoc/uic.html">uic</a> 应该使用哪种方法向容器小部件添加页面。这适用于需要调用特定方法来添加子组件而不是通过传递父组件来添加子组件的容器小部件。特别地，这与那些不是 <i>Qt Designer</i> 中提供的容器的子类，而是基于 <i>当前页面</i> 概念的容器有关。此外，还需要为它们提供一个容器扩展。</p>
<p> <code>&lt;propertyspecifications&gt;</code> 元素可以包含属性元信息列表。</p>
<p>标签 <code>&lt;tooltip&gt;</code> 可用于指定将鼠标悬停在属性上时在属性编辑器中显示的工具提示。属性名在属性 <code>name</code> 中给出，元素文本是工具提示。该功能是在Qt 5.6中添加的 。</p>
<p>对于字符串类型的属性，使用 <code>&lt;stringpropertyspecification&gt;</code> 可以使用标签。这个标签有以下属性:</p>
<div class="table"><table class="generic">
 <thead><tr class="qt-style"><th >属性</th><th >存在</th><th >值</th><th >评论</th></tr></thead>
<tr valign="top" class="odd"><td ><code>name</code></td><td >要求</td><td >属性名</td></tr>
<tr valign="top" class="even"><td ><code>type</code></td><td >要求</td><td >见下表</td><td >属性的值决定了属性编辑器将如何处理它们。</td></tr>
<tr valign="top" class="odd"><td ><code>notr</code></td><td >可选</td><td >&quot;true&quot;, &quot;false&quot;</td><td >如果属性为 &quot;true&quot; ，则不需要转换该值 。</td></tr>
</table></div>
<p>字符串属性的 <code>type</code> 属性值:</p>
<div class="table"><table class="generic">
 <thead><tr class="qt-style"><th >值</th><th >类型</th></tr></thead>
<tr valign="top" class="odd"><td ><code>&quot;richtext&quot;</code></td><td >富文本。</td></tr>
<tr valign="top" class="even"><td ><code>&quot;multiline&quot;</code></td><td >多行文本。</td></tr>
<tr valign="top" class="odd"><td ><code>&quot;singleline&quot;</code></td><td >单行文本。</td></tr>
<tr valign="top" class="even"><td ><code>&quot;stylesheet&quot;</code></td><td >css样式表。</td></tr>
<tr valign="top" class="odd"><td ><code>&quot;objectname&quot;</code></td><td >对象名称(受限制的有效字符集)。</td></tr>
<tr valign="top" class="even"><td ><code>&quot;url&quot;</code></td><td >URL, 文件名。</td></tr>
</table></div>
<a name="plugin-requirements"></a>
<h2 id="plugin-requirements">插件的需求</h2>
<p>为了使插件能够在所有平台上正常工作，您需要确保它们能够导出 <i>Qt Designer</i> 所需要的符号。</p>
<p>首先，插件类必须导出，以便 <i>Qt Designer</i> 加载插件。使用 <a href="../qtcore/qtplugin.html#Q_PLUGIN_METADATA">Q_PLUGIN_METADATA</a>() 宏来完成此操作。另外， <a href="qdesignercustomwidgetinterface.html#QDESIGNER_WIDGET_EXPORT">QDESIGNER_WIDGET_EXPORT</a> 宏必须用于定义 <i>Qt Designer</i> 将实例化的插件中的每个自定义小部件类。</p>
<a name="creating-well-behaved-widgets"></a>
<h2 id="creating-well-behaved-widgets">创建表现良好的小部件</h2>
<p>一些定制小部件具有特殊的用户界面特性，这可能使它们的行为与 <i>Qt Designer</i> 中发现的许多标准小部件不同。具体来说，如果自定义小部件在调用 <a href="../qtwidgets/qwidget.html#grabKeyboard">QWidget::grabKeyboard</a>() 后获取键盘，则 <i>Qt Designer</i> 的操作将受到影响。</p>
<p>要在 <i>Qt Designer</i> 中赋予自定义小部件特殊的行为，请提供 initialize() 函数的实现，以为 <i>Qt Designer</i> 特定的行为配置小部件的构造过程。这个函数将在调用 createWidget() 之前第一次被调用，并且可以设置一个内部标志，以便稍后 <i>Qt Designer</i> 调用插件的 createWidget() 函数时进行测试 。</p>
<a name="buildingandinstallingtheplugin"></a><a name="building-and-installing-the-plugin"></a>
<h2 id="building-and-installing-the-plugin">构建和安装插件</h2>
<a name="a-simple-plugin"></a>
<h3 id="a-simple-plugin">一个简单的插件</h3>
<p>这个 <a href="qtdesigner-customwidgetplugin-example.html">自定义小部件插件示例</a> 演示了一个简单的 <i>Qt Designer</i> 插件。</p>
<p>插件的 <code>.pro</code> 文件必须指定自定义小部件和插件接口的头文件和源文件。通常，这个文件只需要指定插件的项目是作为一个库构建的，但是需要为 <i>Qt Designer</i> 提供特定的插件支持。这是通过以下声明完成的:</p>
<pre class="cpp">

  QT          += widgets uiplugin
  CONFIG      += plugin
  TEMPLATE    = lib

</pre>
<p><code>QT</code> 变量包含关键字 <code>uiplugin</code> 。它表明插件只使用抽象接口 <a href="qdesignercustomwidgetinterface.html">QDesignerCustomWidgetInterface</a> 和 <a  href="qdesignercustomwidgetcollectioninterface.html">QDesignerCustomWidgetCollectionInterface</a> ，并且没有与 <i>Qt Designer</i> 库的链接。在访问其他具有链接的 <i>Qt Designer</i> 接口时，应改用 <code>designer</code> ; 这确保了插件动态链接到 <i>Qt Designer</i> 库，并在运行时依赖于它们 。</p>
<p>如果在与 <i>Qt Designer</i> 不兼容的模式下构建插件，它们将不会被加载和安装。有关插件的更多信息，请参见 <a href="../qtdoc/plugins-howto.html">Plugins HOWTO</a> 文档 。</p>
<p>还需要确保插件与其他 <i>Qt Designer</i> 小部件插件一起安装:</p>
<pre class="cpp">

  target.path = $$[QT_INSTALL_PLUGINS]/designer
  INSTALLS += target

</pre>
<p>变量 <code>$[QT_INSTALL_PLUGINS]</code> 是一个占位符，用于表示已安装的Qt插件的位置。您可以配置 <i>Qt Designer</i> ，在运行应用程序之前通过设置 <code>QT_PLUGIN_PATH</code> 环境变量来在其他位置查找插件。</p>
<p><b>注意: </b> <i>Qt Designer</i> 将在提供的每个路径中查找 <code>designer</code> 子目录。</p><p>有关使用Qt应用程序为库和插件定制路径的更多信息，请参阅 <a href="../qtcore/qcoreapplication.html#libraryPaths">QCoreApplication::libraryPaths</a>() 。</p>
<a name="splitting-up-the-plugin"></a>
<h3 id="splitting-up-the-plugin">分解插件</h3>
<p>在真实的场景中，您不希望应用程序依赖于使用定制小部件的 <i>Qt Designer</i> 头和库，正如前面解释的简单方法所介绍的那样。</p>
<p>下面几节将描述如何解决此问题。</p>
<a name="linking-the-widget-into-the-application"></a>
<h4 id="linking-the-widget-into-the-application">将小部件链接到应用程序中</h4>
<p>自定义小部件的源文件和头文件可以在应用程序和 <i>Qt Designer</i> 之间共享，通过创建一个 <code>.pri</code> 文件来包含:</p>
<pre class="cpp">

  INCLUDEPATH <span class="operator">+</span><span class="operator">=</span> $$PWD
  HEADERS <span class="operator">+</span><span class="operator">=</span> $$PWD<span class="operator">/</span>analogclock<span class="operator">.</span>h
  SOURCES <span class="operator">+</span><span class="operator">=</span> $$PWD<span class="operator">/</span>analogclock<span class="operator">.</span>cpp

</pre>
<p>这个文件会被插件和应用程序的 <code>.pro</code> 文件包含:</p>
<pre class="cpp">

  <span class="keyword">include</span>(customwidget<span class="operator">.</span>pri)

</pre>
<a name="sharing-the-widget-using-a-library"></a>
<h4 id="sharing-the-widget-using-a-library">使用库共享小部件</h4>
<p>另一种方法是将小部件放入一个库中，该库链接到 <i>Qt Designer</i> 插件和应用程序。
建议使用静态库，以避免在运行时查找库时出现问题。</p>
<p>有关共享库，请参见 <a href="../qtdoc/sharedlibrary.html">创建共享库</a> 。</p>
<a name="using-the-plugin-with-quiloader"></a>
<h4 id="using-the-plugin-with-quiloader">使用插件与QUiLoader</h4>
<p>向 <a href="../qtuitools/quiloader.html">QUiLoader</a> 添加定制小部件的首选方法是子类化它，重新实现 <a href="../qtuitools/quiloader.html#createWidget">QUiLoader::createWidget</a>() 。</p>
<p>但是，也可以使用 <i>Qt Designer</i> 定制的小部件插件(参见 <a href="../qtuitools/quiloader.html#pluginPaths">QUiLoader::pluginPaths</a>() 和相关函数)。为了避免将 <i>Qt Designer</i> 库部署到目标设备上，这些插件应该没有与 <i>Qt Designer</i> 库的链接(<code>QT = uiplugin</code>，参见创建自定义小部件的 <a href="designer-creating-custom-widgets.html#buildingandinstallingtheplugin">构建和安装插件</a> 部分)。</p>
<a name="related-examples"></a>
<h2 id="related-examples">相关的例子</h2>
<p>有关在 <i>Qt Designer</i> 中使用自定义小部件的更多信息，请参考 <a href="qtdesigner-customwidgetplugin-example.html">自定义小部件插件</a> 和 <a  href="qtdesigner-worldtimeclockplugin-example.html">世界时间时钟插件</a> 示例，以获得关于在 <i>Qt Designer</i> 中使用自定义小部件的更多信息。另外，还可以使用 <a href="qdesignercustomwidgetcollectioninterface.html">QDesignerCustomWidgetCollectionInterface</a> 类将几个定制小部件组合到一个库中。</p>
</div>
<!-- @@@designer-creating-custom-widgets.html -->
<p class="naviNextPrevious footerNavi">
<a class="prevPage" href="designer-using-custom-widgets.html">使用自定义小部件（Widgets）</a>
<span class="naviSeparator">  &#9702;  </span>
<a class="nextPage" href="designer-creating-custom-widgets-extensions.html">创建自定义小部件(Widget)扩展</a>
</p>
        </div>
       </div>
   </div>
   </div>
</div>
<div class="footer">
   <p>
   <acronym title="Copyright">&copy;</acronym> 2020 The Qt Company Ltd.
   Documentation contributions included herein are the copyrights of
   their respective owners.<br/>    The documentation provided herein is licensed under the terms of the    <a href="http://www.gnu.org/licenses/fdl.html">GNU Free Documentation    License version 1.3</a> as published by the Free Software Foundation.<br/>    Qt and respective logos are trademarks of The Qt Company Ltd.     in Finland and/or other countries worldwide. All other trademarks are property
   of their respective owners. </p>
</div>
</body>
</html>
